package Test_interface

import (
	"fmt"
	"reflect"
)

/*
1,反射的基本概念
反射可以在运行时动态的获取变量的各种信息，比如变量的类型（type），类别（kind）
如果是结构体变量，还可以获取到结构体本身的信息（包括结构体的字段，方法）
通过反射，可以修改变量的值，可以调用关联的方法
使用反射需要import "reflect"
2，反射的应用场景
1）不知道接口调用哪个函数，根据传入的参数在运行时确定调用的具体接口，这种需要对函数或方法进行反射，例如
桥接模式。
	func bridge(funcPtr interface{},args ...interface{})
第一个参数funcPtr以接口的形式传入函数指针，函数参数args以可变参数的形式传入，bridge函数可以用反射来动态执行funcPtr函数
2）对结构体序列化时，如果结构体有指定的Tag，也会使用到反射生成对应的字符串
3，反射的重要函数和概念
1）reflect.TypeOf(变量名),获取变量的类型，返回reflect.Type类型
2）reflect.ValueOf(变量名），获取变量的值，返回reflect.Value类型，reflect.Value是一个结构体类型
通过reflect.Value可以看到很多关于该变量的很多东西，或者通过它的方法来获取对应的值
3）变量，interface{}和reflect.Value是可以相互转换的
变量---传递参数--->interface{}-----reflect.Value()函数---->reflect.Value-----v.interface{}--->interface{}-----类型断言---->变量
 */
//演示对基本数据类型的反射操作
func interfaceReflectInt(num interface{}){
	//1,通过反射获取传入变量的type，kind值
	tp:=reflect.TypeOf(num)//会把当前接口类型的变量变成基本类型
	fmt.Println("type=",tp)//typeOf就是相当于变成tyoe类型的接口
	fmt.Println("kind=",tp.Kind())//这个接口里面有一系列方法
	//2,获取到reflecy.Value
	rVal:=reflect.ValueOf(num)//会将传递过来的数据变成reflect.Value类型的结构体
	fmt.Println(rVal.Int())//事先知道类型进行转换//然后根据类型来进行方法选择
	//3,将reflect.Value变成interface{}
	iv:=rVal.Interface()//将你刚才的reflect.Struct又变成之前你传入的接口
	num2:=iv.(int)
	fmt.Println(num2)
}
type student struct {
	name string
	age int
}
func structReflectInterface(stu interface{}){
	//1，获取Type和Kind值
	rtype:=reflect.TypeOf(stu)
	fmt.Println("type=",rtype)
	fmt.Println("kind=",rtype.Kind())
	//2,获取到reflect.Value
	rVal:=reflect.ValueOf(stu)
	fmt.Println("reflect.value=",rVal)
	fmt.Println("reflect.Value.kind=",rVal.Kind())
	//3,将rVal转成interface{}
	iV:=rVal.Interface()//将student转换成interface
	fmt.Printf("iv=%v,type=%T\n",iV,iV)
	//将interfac{}通过类型断言转成需要的类型
	//这里我们就简单使用了带检测的类型断言
	s,ok:=iV.(student)
	if ok{}
	fmt.Println(s.age,s.name)

}

func Test3()  {
	//interfaceReflectInt(100)
	structReflectInterface(student{name: "wang",age: 10})
}